package ita.class1.group2.supermarket.common.captain.manager;

import ita.class1.group2.supermarket.common.annotation.Autowired;
import ita.class1.group2.supermarket.common.annotation.Component;
import org.apache.log4j.Logger;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class ComponentManager {

    private static final Logger LOGGER = Logger.getLogger(ComponentManager.class);

    private Set<Class<?>> classes = null;
    private Map<Class, Object> componentsMap = null;

    public ComponentManager(Set<Class<?>> classes) {
        this.classes = classes;
        this.componentsMap = new HashMap<Class, Object>();
        initializeComponents();
        injectComponents();
    }

    private void initializeComponents() {
        for (Class cls: classes) {
            if (cls.isAnnotationPresent(Component.class)) {
                try {
                    this.componentsMap.put(cls, cls.newInstance());
                    LOGGER.info("Add component instance: " + cls.getName());
                } catch (Exception e) {
                    LOGGER.error("Can not add component instance: " + cls.getName() + ", Message: " + e.toString());
                }
            }
        }
    }

    private void injectComponents() {
        for (Class cls: classes) {
            if (cls.isAnnotationPresent(Component.class)) {
                autowiredFields(cls, cls);
                if (cls.getSuperclass() != null)
                    autowiredFields(cls.getSuperclass(), cls);
            }
        }
    }

    private void autowiredFields(Class cls, Class objCls) {
        for (Field field: cls.getDeclaredFields()) {
            if (field.isAnnotationPresent(Autowired.class)) {
                field.setAccessible(true);
                try {
                    field.set(this.componentsMap.get(objCls), this.componentsMap.get(field.getType()));
                    LOGGER.info("Autowired field: " + cls.getName() + "." + field.getName());
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public Map<Class, Object> getComponentsMap() {
        return componentsMap;
    }

    public Object getBean(Class cls) {
        return this.componentsMap.get(cls);
    }

}
